import java.util.*;
import java.util.Timer;

import javax.swing.*;
import javax.swing.event.*;

public class TrainModel
{
	private static final String[] STATUS_MESSAGES = {"Train Model :  idle", "Train Model :  bundle from track model received", "Train Model :  bundle to train controller sent"};
	private static byte status = 0;
	private static Map<Integer, TrainModel> id2TrainModel = new HashMap<Integer, TrainModel>();
	private static int idTotal = 0;
	private int id;
	private TrainController associatedTrainController;
//	private double length;
//	private double height;
//	private double width;
	public double mass;
//	private int numberOfCars;
//	private int crewCount;
//	private int passengerCount;
//	private boolean lightsOn;
//	private boolean doorsOpen;
//	private double temperature;
	private double[] accelerationLimits = {150, -50};
//	private double[] velocityLimits;
	private double power = 0;
	private double acceleration = 0;
	public double velocity = 0;
	private double positionOnCurrentTrackBlock = 0;
//	private TrackBlock currentTrackBlock;
	private int authority;
	private int authorityRemaining;
//	private List<TrackBlock> routeInformation;
//	private int failureStatus;

	static
	{
		JFrame frame = new JFrame("Subsystem GUI - Train Model");
		frame.setBounds(730, 165, 470, 150);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().add(new TrainModelJPanel());
		frame.pack();
		frame.setVisible(true);
		
		//main(null);
	}

	public TrainModel(double mass)
	{
		this.id = idTotal++;
		id2TrainModel.put(id, this);
		associatedTrainController = new TrainController(this);
		this.mass                        = mass;
		this.power                       = 0;
		this.acceleration                = 0;
		this.velocity                    = 0;
		this.positionOnCurrentTrackBlock = 0;
		TrainModelJPanel.refresh();
	}

	public TrainModel()
	{
		this(220000);
	}

	public static void sendBundle(TMBundle testTMBundle) throws InterruptedException
	{
		Thread.sleep(3000);

		status = 1;
		TrainModelJPanel.refresh();
		System.out.println(getStatusMessage());

		TNBundle testTNBundle = new TNBundle();
		testTNBundle.newSpeed = testTMBundle.speed;
		testTNBundle.currentSpeed = getTrainModelById(0).getVelocity();
		testTNBundle.mass = getTrainModelById(0).mass;
		testTNBundle.accelerationLimits = getTrainModelById(0).accelerationLimits;

		Thread.sleep(3000);

		status = 2;
		TrainModelJPanel.refresh();
		System.out.println(getStatusMessage());

		getTrainModelById(0).associatedTrainController.receive(testTNBundle);
	}

	static String getStatusMessage()
	{
		return STATUS_MESSAGES[status];
	}

	static TrainModel getTrainModelById(int id)
	{
		return id2TrainModel.get(id);
	}

	/**
	 * Sets the power for the train model and updates the acceleration, velocity, and position on current track block
	 * @param power The power
	 * @return Nothing
	 */
	public void setPower(double power)
	{
		for (double t = 0; velocity < (power / (accelerationLimits[0]*mass)); t += 0.01)
		{
			this.power = power;
			this.acceleration = accelerationLimits[0];
			this.velocity = t * acceleration;
			this.positionOnCurrentTrackBlock = 0.5 * acceleration * t * t;
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			TrainModelJPanel.refresh();
		}
		this.power = 0;
		this.acceleration = 0;
		TrainModelJPanel.refresh();
		this.velocity = 0;
	}
	
	public void setVelocity(double speed)
	{
		this.velocity = speed;
		TrainModelJPanel.refresh();
	}

	double getMass()
	{
		return mass;
	}

	double getPower()
	{
		return power;
	}

	double getAcceleration()
	{
		return acceleration;
	}

	double getVelocity()
	{
		return velocity;
	}

	double getPositionOnCurrentTrackBlock()
	{
		return positionOnCurrentTrackBlock;
	}

	public static void main(String[] args)
	{
		new TrainModel(151122);
		new TrainModel(235553);
		new TrainModel(200000);
		System.out.println("3 trains created.");
	}
}

class TrainModelJPanel extends JPanel
{
	private static JLabel status;
	private static JLabel idLabel;
	private static JLabel massLabel;
	private static JLabel powerLabel;
	private static JLabel accelerationLabel;
	private static JLabel velocityLabel;
	private static JLabel positionOnCurrentTrackBlockLabel;
	private static JSpinner id;
	private static JTextField mass;
	private static JTextField power;
	private static JTextField acceleration;
	private static JTextField velocity;
	private static JTextField positionOnCurrentTrackBlock;
	private static JSeparator jSeparator1;
	private static JSeparator jSeparator2;

	public TrainModelJPanel()
	{
		status                           = new JLabel();
		idLabel                          = new JLabel();
		massLabel                        = new JLabel();
		powerLabel                       = new JLabel();
		accelerationLabel                = new JLabel();
		velocityLabel                    = new JLabel();
		positionOnCurrentTrackBlockLabel = new JLabel();
		id                               = new JSpinner();
		mass                             = new JTextField();
		power                            = new JTextField();
		acceleration                     = new JTextField();
		velocity                         = new JTextField();
		positionOnCurrentTrackBlock      = new JTextField();
		jSeparator1                      = new JSeparator();
		jSeparator2                      = new JSeparator();

		status                         .setText("Bundle status:");
		idLabel                         .setText("Train ID");
		massLabel                       .setText("Mass (kg)");
		powerLabel                      .setText("Power (W)");
		accelerationLabel               .setText("Acceleration (m/s^2)");
		velocityLabel                   .setText("Velocity (m/s)");
		positionOnCurrentTrackBlockLabel.setText("Position on current track block (m)");

		id.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent evt) {
				refresh();
			}
		});

		GroupLayout layout = new GroupLayout(this);
		this.setLayout(layout);
		layout.setHorizontalGroup(
			layout.createParallelGroup(GroupLayout.Alignment.LEADING)
			.addGroup(layout.createSequentialGroup()
				.addContainerGap()
				.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
					.addGroup(layout.createSequentialGroup()
						.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
							.addComponent(positionOnCurrentTrackBlockLabel)
							.addComponent(velocityLabel)
							.addComponent(accelerationLabel)
							.addComponent(powerLabel)
							.addComponent(massLabel)
							.addComponent(idLabel))
						.addGap(18, 18, 18)
						.addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
							.addComponent(id, GroupLayout.DEFAULT_SIZE, 218, Short.MAX_VALUE)
							.addComponent(mass)
							.addComponent(power)
							.addComponent(acceleration)
							.addComponent(velocity)
							.addComponent(positionOnCurrentTrackBlock)))
					.addComponent(status)
					.addComponent(jSeparator1)
					.addComponent(jSeparator2))
				.addContainerGap())
		);
		layout.setVerticalGroup(
			layout.createParallelGroup(GroupLayout.Alignment.LEADING)
			.addGroup(layout.createSequentialGroup()
				.addGap(11, 11, 11)
				.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
					.addComponent(status, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
				.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
				.addComponent(jSeparator1, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
				.addGap(11, 11, 11)
				.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
					.addComponent(idLabel)
					.addComponent(id, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
				.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
				.addComponent(jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE)
				.addGap(11, 11, 11)
				.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
					.addComponent(massLabel)
					.addComponent(mass, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
				.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
				.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
					.addComponent(powerLabel)
					.addComponent(power, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
				.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
				.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
					.addComponent(accelerationLabel)
					.addComponent(acceleration, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
				.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
				.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
					.addComponent(velocityLabel)
					.addComponent(velocity, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
				.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
				.addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
					.addComponent(positionOnCurrentTrackBlockLabel)
					.addComponent(positionOnCurrentTrackBlock, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
				.addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
		);

		refresh();
	}

	public static void refresh()
	{
		status.setText(TrainModel.getStatusMessage());
		TrainModel thisTrainModel = TrainModel.getTrainModelById((Integer)id.getValue());
		if (thisTrainModel == null)
		{
			mass                       .setText("N/A");
			power                      .setText("N/A");
			acceleration               .setText("N/A");
			velocity                   .setText("N/A");
			positionOnCurrentTrackBlock.setText("N/A");
		}
		else
		{
			mass                       .setText("" + thisTrainModel.getMass());
			power                      .setText("" + thisTrainModel.getPower());
			acceleration               .setText("" + thisTrainModel.getAcceleration());
			velocity                   .setText("" + thisTrainModel.getVelocity());
			positionOnCurrentTrackBlock.setText("" + thisTrainModel.getPositionOnCurrentTrackBlock());
		}
	}		
}
